home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / Delphi 3.0 / DATA.Z / checklst.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-01-29  |  11.3 KB  |  443 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {       Delphi Visual Component Library                 }
  4. {                                                       }
  5. {       Copyright (c) 1997 Borland International        }
  6. {                                                       }
  7. {*******************************************************}
  8.  
  9. unit checklst;
  10.  
  11. interface
  12.  
  13. uses
  14.   Windows, Messages, SysUtils, Classes, Graphics, Controls, 
  15.   StdCtrls;
  16.  
  17. type
  18.   TCheckListBox = class(TCustomListBox)
  19.   private
  20.     FAllowGrayed: Boolean;
  21.     FStandardItemHeight: Integer;
  22.     FOnClickCheck: TNotifyEvent;
  23.     FSaveStates: TList;
  24.     procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM;
  25.     procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  26.     procedure ResetItemHeight;
  27.     procedure DrawCheck( R: TRect; AState: TCheckBoxState );
  28.     procedure SetChecked( Index: Integer; Checked: Boolean );
  29.     function GetChecked( Index: Integer ): Boolean;
  30.     procedure SetState( Index: Integer; AState: TCheckBoxState );
  31.     function GetState( Index: Integer ): TCheckBoxState;
  32.     procedure ToggleClickCheck( Index: Integer );
  33.     procedure InvalidateCheck( Index: Integer );
  34.     function CreateWrapper( Index: Integer ): TObject;
  35.     function ExtractWrapper( Index: Integer ): TObject;
  36.     function GetWrapper( Index: Integer): TObject;
  37.     function HaveWrapper( Index: Integer): Boolean;
  38.   protected
  39.     procedure DrawItem(Index: Integer; Rect: TRect;
  40.       State: TOwnerDrawState); override;
  41.     procedure SetItemData( Index: Integer; AData: LongInt ); override;
  42.     function GetItemData( Index: Integer ): LongInt; override;
  43.     procedure KeyPress(var Key: Char); override;
  44.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  45.       X, Y: Integer); override;
  46.     procedure ResetContent; override;
  47.     procedure DeleteString(Index: Integer); override;
  48.     procedure ClickCheck; dynamic;
  49.     procedure CreateParams(var Params: TCreateParams); override;
  50.     procedure CreateWnd; override;
  51.     procedure DestroyWnd; override;
  52.     function GetCheckWidth: Integer;
  53.   public
  54.     destructor Destroy; override;
  55.     property Checked[Index: Integer]: Boolean read GetChecked write SetChecked;
  56.     property State[Index: Integer]: TCheckBoxState read GetState write SetState;
  57.   published
  58.     property OnClickCheck: TNotifyEvent read FOnClickCheck write FOnClickCheck;
  59.     property Align;
  60.     property AllowGrayed: Boolean read FAllowGrayed write FAllowGrayed default False;
  61.     property BorderStyle;
  62.     property Color;
  63.     property Columns;
  64.     property Ctl3D;
  65.     property DragCursor;
  66.     property DragMode;
  67.     property Enabled;
  68.     //property ExtendedSelect;
  69.     property Font;
  70.     property ImeMode;
  71.     property ImeName;
  72.     property IntegralHeight;
  73.     property ItemHeight;
  74.     property Items;
  75.     //property MultiSelect;
  76.     property ParentColor;
  77.     property ParentCtl3D;
  78.     property ParentFont;
  79.     property ParentShowHint;
  80.     property PopupMenu;
  81.     property ShowHint;
  82.     property Sorted;
  83.     property Style;
  84.     property TabOrder;
  85.     property TabStop;
  86.     property TabWidth;
  87.     property Visible;
  88.     property OnClick;
  89.     property OnDblClick;
  90.     property OnDragDrop;
  91.     property OnDragOver;
  92.     property OnDrawItem;
  93.     property OnEndDrag;
  94.     property OnEnter;
  95.     property OnExit;
  96.     property OnKeyDown;
  97.     property OnKeyPress;
  98.     property OnKeyUp;
  99.     property OnMeasureItem;
  100.     property OnMouseDown;
  101.     property OnMouseMove;
  102.     property OnMouseUp;
  103.     property OnStartDrag;
  104.   end;
  105.  
  106. implementation
  107.  
  108.  
  109. type
  110.  
  111.   TCheckListBoxDataWrapper = class
  112.   private
  113.     FData: LongInt;
  114.     FState: TCheckBoxState;
  115.     procedure SetChecked( Check: Boolean );
  116.     function GetChecked: Boolean;
  117.   public
  118.     class function GetDefaultState: TCheckBoxState;
  119.     property Checked: Boolean read GetChecked write SetChecked;
  120.     property State: TCheckBoxState read FState write FState;
  121.   end;
  122.  
  123.  
  124.  
  125. var
  126.   FCheckWidth, FCheckHeight: Integer;
  127.  
  128. procedure GetCheckSize;
  129. begin
  130.   with TBitmap.Create do
  131.     try
  132.       Handle := LoadBitmap( 0, PChar(32759) );
  133.       FCheckWidth := Width div 4;
  134.       FCheckHeight := Height div 3;
  135.     finally
  136.       Free;
  137.     end;
  138. end;
  139.  
  140. { TCheckListBoxDataWrapper }
  141. procedure TCheckListBoxDataWrapper.SetChecked( Check: Boolean );
  142. begin
  143.   if Check then FState := cbChecked else FState := cbUnchecked;
  144. end;
  145.  
  146. function TCheckListBoxDataWrapper.GetChecked: Boolean;
  147. begin
  148.   Result := FState = cbChecked;
  149. end;
  150.  
  151. class function TCheckListBoxDataWrapper.GetDefaultState: TCheckBoxState;
  152. begin
  153.   Result := cbUnchecked;
  154. end;
  155.  
  156. { TCheckListBox }
  157. destructor TCheckListBox.Destroy;
  158. begin
  159.   FSaveStates.Free;
  160.   inherited;
  161. end;
  162.  
  163. procedure TCheckListBox.CreateWnd;
  164. var
  165.   I: Integer;
  166. begin
  167.   inherited CreateWnd;
  168.   if FSaveStates <> nil then
  169.   begin
  170.     for I := 0 to Items.Count -1 do
  171.       State[I] := TCheckBoxState(FSaveStates[I]);
  172.     FSaveStates.Free;
  173.     FSaveStates := nil;
  174.   end;
  175.   ResetItemHeight;
  176. end;
  177.  
  178. procedure TCheckListBox.DestroyWnd;
  179. var
  180.   I: Integer;
  181.   FWrappers: TList;
  182. begin
  183.   FWrappers := nil;
  184.   if Items.Count > 0 then
  185.   begin
  186.     FSaveStates := TList.Create;
  187.     FWrappers := TList.Create;
  188.     for I := 0 to Items.Count -1 do
  189.     begin
  190.       FSaveStates.Add( TObject( State[I]) );
  191.       FWrappers.Add( ExtractWrapper( I ) );
  192.     end;
  193.   end;
  194.   inherited DestroyWnd;
  195.   if FWrappers <> nil then
  196.   begin
  197.     for I := 0 to FWrappers.Count-1 do
  198.       TCheckListBoxDataWrapper(FWrappers[I]).Free;
  199.     FWrappers.Free;
  200.   end;
  201. end;
  202.  
  203. procedure TCheckListBox.CreateParams(var Params: TCreateParams);
  204. begin
  205.   inherited;
  206.   with Params do
  207.     if Style and (LBS_OWNERDRAWFIXED or LBS_OWNERDRAWVARIABLE ) = 0 then
  208.       Style := Style or LBS_OWNERDRAWFIXED;
  209. end;
  210.  
  211. function TCheckListBox.GetCheckWidth: Integer;
  212. begin
  213.   Result := FCheckWidth + 2;
  214. end;
  215.  
  216. procedure TCheckListBox.CMFontChanged(var Message: TMessage);
  217. begin
  218.   inherited;
  219.   ResetItemHeight;
  220. end;
  221.  
  222. procedure TCheckListBox.ResetItemHeight;
  223. begin
  224.   if Style = lbStandard then
  225.   begin
  226.     Canvas.Font := Font;
  227.     FStandardItemHeight := Canvas.TextHeight('Wg');
  228.     Perform(LB_SETITEMHEIGHT, 0, FStandardItemHeight);
  229.   end;
  230. end;
  231.  
  232.  
  233. procedure TCheckListBox.DrawItem(Index: Integer; Rect: TRect;
  234.   State: TOwnerDrawState);
  235. var
  236.   R: TRect;
  237.   SaveEvent: TDrawItemEvent;
  238. begin
  239.  
  240.   if Index < Items.Count then
  241.   begin
  242.     R := Rect;
  243.     R.Right := Rect.Left;
  244.     R.Left := R.Right - GetCheckWidth;
  245.     DrawCheck( R, GetState( Index ) );
  246.   end;
  247.  
  248.   if (Style = lbStandard) and Assigned(OnDrawItem) then
  249.   begin
  250.     // Force lbStandard list to ignore OnDrawItem event.
  251.     SaveEvent := OnDrawItem;
  252.     OnDrawItem := nil;
  253.     try
  254.       inherited;
  255.     finally
  256.       OnDrawItem := SaveEvent;
  257.     end;
  258.   end
  259.   else
  260.     inherited;
  261. end;
  262.  
  263.  
  264. procedure TCheckListBox.CNDrawItem(var Message: TWMDrawItem);
  265. begin 
  266.     with Message.DrawItemStruct^ do
  267.         rcItem.Left := rcItem.Left + GetCheckWidth;
  268.     inherited;
  269. end;
  270.  
  271.  
  272. procedure TCheckListBox.DrawCheck( R: TRect; AState: TCheckBoxState );
  273. var
  274.   DrawState: Integer;
  275.   DrawRect: TRect;
  276. begin
  277.   case AState of
  278.     cbChecked:
  279.       DrawState := DFCS_BUTTONCHECK or DFCS_CHECKED;
  280.     cbUnchecked:
  281.       DrawState := DFCS_BUTTONCHECK;
  282.     else // cbGrayed
  283.       DrawState := DFCS_BUTTON3STATE or DFCS_CHECKED;
  284.   end;
  285.   DrawRect.Left := R.Left + (R.Right - R.Left - FCheckWidth) div 2;
  286.   DrawRect.Top := R.Top + (R.Bottom - R.Top - FCheckWidth) div 2;
  287.   DrawRect.Right := DrawRect.Left + FCheckWidth;
  288.   DrawRect.Bottom := DrawRect.Top + FCheckHeight;
  289.  
  290.   DrawFrameControl( Canvas.Handle,
  291.      DrawRect,  DFC_BUTTON,  DrawState);
  292.  
  293. end;
  294.  
  295.  
  296.  
  297. procedure TCheckListBox.SetChecked( Index: Integer; Checked: Boolean );
  298. begin
  299.   if Checked <> GetChecked( Index ) then
  300.   begin
  301.     TCheckListBoxDataWrapper(GetWrapper(Index)).SetChecked( Checked );
  302.     InvalidateCheck( Index );
  303.   end;
  304. end;
  305.  
  306. procedure TCheckListBox.SetState( Index: Integer; AState: TCheckBoxState );
  307. begin
  308.   if AState <> GetState( Index ) then
  309.   begin
  310.     TCheckListBoxDataWrapper(GetWrapper(Index)).State := AState;
  311.     InvalidateCheck( Index );
  312.   end;
  313. end;
  314.  
  315. procedure TCheckListBox.InvalidateCheck( Index: Integer );
  316. var
  317.   R: TRect;
  318. begin
  319.   R := ItemRect( Index );
  320.   R.Right := R.Left + GetCheckWidth;
  321.   InvalidateRect(Handle, @R, not (csOpaque in ControlStyle));
  322.   UpdateWindow(Handle);
  323. end;
  324.  
  325. function TCheckListBox.GetChecked( Index: Integer ): Boolean;
  326. begin
  327.   if HaveWrapper( Index ) then
  328.     Result := TCheckListBoxDataWrapper(GetWrapper(Index)).GetChecked
  329.   else
  330.     Result := False;
  331. end;
  332.  
  333. function TCheckListBox.GetState( Index: Integer ): TCheckBoxState;
  334. begin
  335.   if HaveWrapper( Index ) then
  336.     Result := TCheckListBoxDataWrapper(GetWrapper(Index)).State
  337.   else
  338.     Result := TCheckListBoxDataWrapper.GetDefaultState;
  339. end;
  340.  
  341. procedure TCheckListBox.KeyPress(var Key: Char);
  342. begin
  343.   inherited;
  344.   if (Key = ' ') then ToggleClickCheck( ItemIndex );
  345. end;
  346.  
  347. procedure TCheckListBox.MouseDown(Button: TMouseButton; Shift: TShiftState;
  348.       X, Y: Integer);
  349. var
  350.   Index: Integer;
  351. begin
  352.   inherited;
  353.   Index := ItemAtPos(Point(X,Y),True);
  354.   if Index <> -1 then
  355.     if X - ItemRect(Index).Left < GetCheckWidth then
  356.       ToggleClickCheck(Index);
  357. end;
  358.  
  359.  
  360. procedure TCheckListBox.ToggleClickCheck;
  361. var
  362.   State: TCheckBoxState;
  363. begin
  364.   if (Index >= 0) and (Index < Items.Count) then
  365.   begin
  366.     State := Self.State[Index];
  367.     case State of
  368.       cbUnchecked:
  369.         if AllowGrayed then State := cbGrayed else State := cbChecked;
  370.       cbChecked: State := cbUnchecked;
  371.       cbGrayed: State := cbChecked;
  372.     end;
  373.     Self.State[Index] := State;
  374.  
  375.     ClickCheck;
  376.   end;
  377. end;
  378.  
  379. procedure TCheckListBox.ClickCheck;
  380. begin
  381.   if Assigned(FOnClickCheck) then FOnClickCheck(Self);
  382. end;
  383.  
  384. function TCheckListBox.GetItemData(Index: Integer): LongInt;
  385. begin
  386.   Result := 0;
  387.   if HaveWrapper( Index ) then
  388.     Result := TCheckListBoxDataWrapper(GetWrapper(Index)).FData;
  389. end;
  390.  
  391. function TCheckListBox.GetWrapper( Index: Integer ): TObject;
  392. begin
  393.   Result := ExtractWrapper( Index );
  394.   if Result = nil then
  395.     Result := CreateWrapper( Index );
  396. end;
  397.  
  398. function TCheckListBox.ExtractWrapper( Index: Integer ): TObject;
  399. begin
  400.   Result := TCheckListBoxDataWrapper(inherited GetItemData( Index ));
  401.   if (Result <> nil) and (not (Result is TCheckListBoxDataWrapper)) then
  402.     Result := nil;
  403. end;
  404.  
  405. function TCheckListBox.CreateWrapper( Index: Integer ): TObject;
  406. begin
  407.   Result := TCheckListBoxDataWrapper.Create;
  408.   inherited SetItemData( Index, LongInt(Result) );
  409. end;
  410.  
  411. function TCheckListBox.HaveWrapper( Index: Integer ): Boolean;
  412. begin
  413.   Result := ExtractWrapper( Index ) <> nil;
  414. end;
  415.  
  416. procedure TCheckListBox.SetItemData(Index: Integer; AData: LongInt);
  417. begin
  418.   TCheckListBoxDataWrapper(GetWrapper( Index )).FData := AData;
  419. end;
  420.  
  421.  
  422. procedure TCheckListBox.ResetContent;
  423. var
  424.   I: Integer;
  425. begin
  426.   for I := 0 to Items.Count - 1 do
  427.     if HaveWrapper(I) then
  428.       GetWrapper( I ).Free;
  429.   inherited;
  430. end;
  431.  
  432. procedure TCheckListBox.DeleteString(Index: Integer);
  433. begin
  434.   if HaveWrapper(Index) then
  435.     GetWrapper( Index ).Free;
  436.   inherited;
  437. end;
  438.  
  439. initialization
  440.   GetCheckSize;
  441.  
  442. end.
  443.